package com.adwyxx.collection;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * {@link List} 接口：除了从Collection集合继承的方法外，List 集合里添加了一些根据`索引`来操作集合元素的方法
 * <pre>
 * 插入元素
 * - void add(int index, Object ele):在index位置插入ele元素
 * - boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
 * 获取元素
 * - Object get(int index):获取指定index位置的元素
 * - List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
 * 获取元素索引
 * - int indexOf(Object obj):返回obj在集合中首次出现的位置
 * - int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
 * 删除和替换元素
 * - Object remove(int index):移除指定index位置的元素，并返回此元素
 * - Object set(int index, Object ele):设置指定index位置的元素为ele
 * </pre>
 * List接口的常用实现类：
 * <pre>
 * - ArrayList 作为默认选择。
 * - LinkedList: 当插入、删除频繁时使用。
 * - Vector: 线程安全的，总是比ArrayList慢，所以尽量避免使用。
 * </pre>
 * 线程安全：
 * <pre>
 * java.util.ConcurrentModificationException 异常是在使用迭代器对集合进行遍历时，如果集合的结构被并发修改，那么迭代器就会抛出这个异常。并发修改意味着在使用迭代器遍历集合的过程中，集合被直接修改了（比如添加、删除元素），而不是通过迭代器自己的方法（如 iterator.remove()）进行修改。
 * 解决方法：
 * 1.使用迭代器自带的 remove() 方法删除元素，而不是集合自身的 remove() 方法。
 * 2.如果需要在遍历过程中添加或删除元素，可以考虑使用并发集合，如 CopyOnWriteArrayList 或者其他专门设计用于多线程情况下的集合类。
 * 3.对于 LinkedList，如果不是在多线程环境下，可以考虑使用传统的 for 循环遍历，并且在循环过程中对列表进行修改。
 * 4.如果在多线程环境下，应当对集合的操作进行同步，使用 synchronized 块或 ReentrantLock 锁来保护集合。
 *</pre>
 * List接口的继承关系：
 *<pre>
 * [Iterable<T>]
 *       ↓
 * [Collection<E>] -> [Queue<E>] -> [Deque<E>]
 *       ↓                                 ↓
 *    [List<E>] -> [AbstractList] |-> [LinkedList] // 双端队列，线程不安全的
 *                                |-> [ArrayList]  // 线程不安全的
 *                                |-> [Vector]     // 线程安全的
 *
 * </pre>
 * @author Leo.W
 * @date 2024-09-14 9:48
 */
public class ListDemo {
    public static void main(String[] args) {
        // ArrayList 作为数组实现，适合随机访问操作时使用
        ArrayList<String> list = new ArrayList();
        list.add("hello");
        list.add("world");
        // 在index位置插入元素
        list.add(0,"ArrayList");
        System.out.println(list); // [ArrayList, hello, world]

        // LinkedList 作为双向链表实现，适合频繁的插入\删除操作时使用
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("A");
        linkedList.addLast("B");
        linkedList.addFirst("LinkedList");
        System.out.println(linkedList); // [LinkedList, A, B]

        // Vector 线程安全，但效率较低
        Vector<String> vector = new Vector<>();
        vector.add("Vector");

        // ArrayList 实现线程安全的方法：
        // List<String> list = Collections.synchronizedList(new ArrayList<>());
        // List<String> list = new CopyOnWriteArrayList<>();
        List<String> syncArrayList = Collections.synchronizedList(new ArrayList<>());
        syncArrayList.add("syncArrayList");
        // LinkedList 实现线程安全的方法：
        List<String> syncLinkedList = Collections.synchronizedList(new LinkedList<>());
        syncLinkedList.add("syncLinkedList");
        // 测试多线程下ArrayList、LinkedList、Vector的线程安全性
        CountDownLatch latch = new CountDownLatch(5);
        ExecutorService taskExecutor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        String v = String.valueOf(i);
                        list.add(v);
                        linkedList.add(v);
                        syncArrayList.add(v);
                        syncLinkedList.add(v);
                        vector.add(v);
                        // Thread.sleep(100);
                    }
                    latch.countDown();
                }
            };
            taskExecutor.execute(task);
        }

        try {
            latch.await(); // 当前线程等待，直到计数为0
            System.out.println(list);
            System.out.println(syncArrayList);
            System.out.println(syncLinkedList);
            System.out.println(vector);
            //System.out.println(linkedList);
        } catch (InterruptedException | ConcurrentModificationException e) {
            // 因为 ArrayList LinkedList 不是线程安全的，所以在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常。
            e.printStackTrace();
        } finally {
            taskExecutor.shutdown();
        }
    }
}
